
#include <BKeyEvent>
#include <BMouseEvent>
#include <BFocusEvent>
#include <BCamera>
#include <BViewer>
#include <BRender>
#include <BPainter>
#include <BFont>
#include <BScene>

#include <BSphereControl>
#include "member_BSphereControl.h"

using namespace BWE;

#define member					(*(member_BSphereControl*)_ptr)
#define member_allocate()		_ptr = new member_BSphereControl(this)
#define member_release()		delete (member_BSphereControl*)_ptr

BSphereControl::BSphereControl()
{
	member_allocate();
}
BSphereControl::~BSphereControl()
{
	member_release();
}

void BSphereControl::setHome(const BVector& position, const BVector& center, const BVector& up)
{
	member.homePosition = position;
	member.homeCenter = center;
	member.homeUp = up;
}
void BSphereControl::home()
{
	BCamera* camera = this->camera();
	if (!camera)
		return;

	BVector position = member.homePosition;
	BVector center = member.homeCenter;
	BVector up = member.homeUp;

	if ((position - center).length() < 1e-5)
	{
		BSpace space = this->viewer()->scene()->space();
		float radius = space.radius();
		if (radius < 1e-5)
			radius = 1.0f;
		center = space.center();
		float fovy = camera->fovy() * 0.5f * PI / 180.0f;;
		float dist = radius / tan(fovy);
		BVector vec(0.0f, -1.0f, 1.0f);
		vec.normalize();
		position = center + vec * dist;
		up.set(0.0f, 0.0f, 1.0f);
	}

	camera->setPosition(position);
	camera->setCenter(center);
	camera->setUp(up);
	this->viewer()->fresh();
}

void BSphereControl::setMoveStep(float moveStep)
{
	member.moveStep = moveStep;
}
float BSphereControl::moveStep() const
{
	return member.moveStep;
}

void BSphereControl::setRotateStep(float rotateStep)
{
	member.rotateStep = rotateStep;
}
float BSphereControl::rotateStep() const
{
	return member.rotateStep;
}

void BSphereControl::paint(BPainter& painter)
{

}
void BSphereControl::render(BRender& render)
{
	//render.drawPoint(member.test0);
	//render.drawPoint(member.test1);
	//render.drawLine(member.testLine);
}

bool BSphereControl::keyDownEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();

	BCamera* camera = this->camera();
	if (camera && key == Key_Space)
	{
		this->home();
		return true;
	}

	return false;
}
bool BSphereControl::keyUpEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();

	return false;
}

bool BSphereControl::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.rightDown = false;
	member.middleDown = false;
	return false;
}
bool BSphereControl::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	member.rightDown = false;
	member.middleDown = false;
	return false;
}

bool BSphereControl::mousePressEvent(const BMouseEvent& mouseEvent)
{
	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (button == Button_Right)
	{
		member.rightDown = true;
		member.rightDownPos = pos;
		return true;
	}
	if (button == Button_Middle)
	{
		member.middleDown = true;
		member.middleDownPos = pos;
		return true;
	}
	return false;
}
bool BSphereControl::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (button == Button_Right)
	{
		member.rightDown = false;
	}
	if (button == Button_Middle)
	{
		member.middleDown = false;
	}
	return false;
}
bool BSphereControl::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (member.rightDown && member.middleDown)
		return false;

	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (member.rightDown)
	{
		if (member.rightDownPos == pos)
			return false;

		BCamera* camera = this->camera();
		BVector position = camera->position();
		BVector center = camera->center();
		BVector up = camera->up();
		up.normalize();

		BVector direct = center - position;
		BVector vec = -direct;
		float length = direct.length();

		BVector right = direct.cross(up);
		right.normalize();

		up = right.cross(direct);
		up.normalize();

		float rotateStep = (float)(this->rotateStep() * PI / 180.0);
		BPoint offset = pos - member.rightDownPos;
		BQuater hquater(rotateStep * offset.x(), -up);
		vec *= hquater;
		BQuater vquater(rotateStep * offset.y(), -right);
		vec *= vquater;
		BVector newPosition = center + vec;
		camera->setPosition(newPosition);
		camera->setCenter(center);
		member.rightDownPos = pos;
		viewer()->fresh();
		return true;
	}
	if (member.middleDown)
	{
		if (member.middleDownPos == pos)
			return false;
		BCamera* camera = this->camera();
		BVector position = camera->position();
		BVector center = camera->center();
		BVector direct = center - position;
		BVector vec = -direct;
		float length = direct.length();

		BVector up = camera->up();
		up.normalize();

		BVector right = direct.cross(up);
		right.normalize();

		up = right.cross(direct);
		up.normalize();

		BViewer* viewer = this->viewer();
		BVector v0 = viewer->vertex(pos, length);
		BVector v1 = viewer->vertex(member.middleDownPos, length);
		BVector offset = v1 - v0;
		camera->setPosition(position + offset);
		camera->setCenter(center + offset);
		member.middleDownPos = pos;

		member.test0 = v0;
		member.test1 = v1;
		member.testLine.set(member.test0, member.test1);
		viewer->fresh();
		return true;
	}
	return false;
}
bool BSphereControl::mouseWheelEvent(const BMouseEvent& mouseEvent)
{
	float moveStep = this->moveStep();
	BCamera* camera = this->camera();
	if (camera->ortho())
	{
		double midx = (camera->right() + camera->left()) * 0.5;
		double midy = (camera->top() + camera->bottom()) * 0.5;
		double height = (camera->top() - camera->bottom()) * (1 + mouseEvent.wheel() * 0.01);
		double width = height * camera->aspect();
		camera->setLeft(midx - width * 0.5);
		camera->setRight(midx + width * 0.5);
		camera->setBottom(midy - height * 0.5);
		camera->setTop(midy + height * 0.5);
		this->viewer()->fresh();
	}
	else
	{
		BVector pos = camera->position();
		BVector center = camera->center();
		BVector direct = center - pos;
		BVector move = direct * (moveStep * mouseEvent.wheel() / 100.0f);
		camera->setPosition(pos - move);
		this->viewer()->fresh();
	}
	return true;
}


